http2: avoid uaf while receiving and sending rst_stream#64166
Conversation
|
Review requested:
|
|
Can you use "-s" (for Signed-off-by) in first commit command, after run this command after: |
Mark the session as receiving around nghttp2_session_mem_recv() and defer RST_STREAM handling while receive is in progress. This prevents closing a stream while nghttp2 still processes it and avoids heap-use-after-free in nghttp2_session_mem_recv2(). Fixes: nodejs#64113 Signed-off-by: Evgeniy Gorbanev <gorbanev.es@gmail.com>
|
Is everything correct now? |
RafaelGSS
left a comment
There was a problem hiding this comment.
Can you add a test case or an script that we could reproduce it?
The scripts are in the issue #64113 |
| // Do not call `nghttp2_session_mem_send()` while nghttp2 is processing | ||
| // incoming data. Sending may close the stream and free nghttp2 state | ||
| // that is still in use by `nghttp2_session_mem_recv()`. | ||
| if (session_->is_receiving() && available_outbound_length_ == 0) { |
There was a problem hiding this comment.
I think available_outbound_length_ == 0 still leaves the exact same UAF issue for the pending-writes case. E.g. if you write any data during a receive callback and then reset, this check would be false, and we'll miss this fix but hit the old UAF behaviour regardless.
I haven't tested this but looks very plausible, let me know if I've missed something.
If you move & invert (>0) the check into the inner if (so we always reset here in all receive cases, but we defer the reset for both cancel codes and pending-writes) then that'd cover this case as well.
|
If you mean replace the code with this then it fixes uaf, but I get these failed tests: Or if I misunderstood you, please write your version. |
|
Ah, interesting, yes we'll have to investigate that @Eusgor. I took a bit more of a look, I think this is part of a bigger more fundamental issue - the nghttp2 docs say:
And in this method, we call The tests are reasonable (e.g. destroy after write - it should flush the written data before the stream is destroyed) but this method we're changing isn't - it should never call I had Claude do a quick scan, there's at least three places we ignore this nghttp2 requirement:
All of those are issues (good find!) and the new Can you take a look? Really I think we need to always defer anything anything that could call one of those methods while receiving - that means something like early-return in |
Mark the session as receiving around nghttp2_session_mem_recv() and defer RST_STREAM handling while receive is in progress. This prevents closing a stream while nghttp2 still processes it and avoids heap-use-after-free in nghttp2_session_mem_recv2().
Fixes: #64113